home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / DevBitmap.C < prev    next >
C/C++ Source or Header  |  1992-08-26  |  12KB  |  546 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "DevBitmap.h"
  6.  
  7. #include "WindowPort.h"
  8. #include "WindowColorMap.h"
  9. #include "Error.h"
  10.  
  11. #define CACHESIZE 40
  12.  
  13. struct BitmapCache {
  14.     int clock, wcmid;
  15.     DevBitmap *org, *dbm;
  16. } Cache[CACHESIZE];
  17.  
  18. static int cacheclock;
  19. static int lastix;
  20.  
  21. inline int PaddedBytesPerLine(int w, int depth, u_short pad)
  22. {
  23.     return ((w-1)/(pad*8)+1)*depth;
  24. }
  25.  
  26. //---- DevBitmap ---------------------------------------------------------------
  27.  
  28. DevBitmap::DevBitmap(Point sz, u_short dep)
  29. {
  30.     refcnt= 0;
  31.     size= sz;
  32.     depth= dep;
  33.     cmap= 0;
  34. }
  35.  
  36. DevBitmap::DevBitmap(DevBitmap *dbm)
  37. {
  38.     refcnt= 0;
  39.     size= dbm->size;
  40.     depth= dbm->depth;
  41.     if (dbm->cmap)
  42.     cmap= new ColorMap(dbm->cmap);
  43.     else
  44.     cmap= 0;
  45. }
  46.  
  47. void DevBitmap::Unref()
  48. {
  49.     if (refcnt > 0) {
  50.     refcnt--;
  51.     if (refcnt == 0)
  52.         delete this;
  53.     }
  54. }
  55.  
  56. DevBitmap::~DevBitmap()
  57. {
  58.     register BitmapCache *bmp= Cache;
  59.     for (int i= 0; i < CACHESIZE; i++, bmp++) {
  60.     if (bmp->org == this || bmp->dbm == this) {
  61.         DevBitmap *o1= bmp->org, *o2= bmp->dbm;
  62.         bmp->org= bmp->dbm= 0;
  63.         if (o1)
  64.         o1->Unref();
  65.         if (o2)
  66.         o2->Unref();
  67.         bmp->org= 0;
  68.         bmp->wcmid= 0;
  69.         bmp->clock= 0;
  70.     }
  71.     }
  72.     SafeDelete(cmap);
  73. }
  74.  
  75. DevBitmap *DevBitmap::DeepClone()
  76. {
  77.     DevBitmap *dbm= DevAllocBitmap(size, depth);
  78.     dbm->cmap= cmap ? new ColorMap(cmap) : 0;
  79.     dbm->DevBitBlt(0, 0, size.x, size.y, TRUE, this, 0, 0);
  80.     return dbm;
  81. }
  82.  
  83. void DevBitmap::DevMapColors(DevBitmap *src, u_long *map)
  84. {
  85.     register int x, y;
  86.     
  87.     for (x= 0; x < size.x; x++)
  88.     for (y= 0; y < size.y; y++)
  89.         SetPixel(x, y, map[src->GetPixel(x, y)]);
  90. }
  91.  
  92. int DevBitmap::BytesPerLine()
  93. {
  94.     return PaddedBytesPerLine(size.x, depth, 1);
  95. }
  96.  
  97. int DevBitmap::GetColormapSize()
  98. {
  99.     if (cmap)
  100.     return cmap->Size();
  101.     return 0;
  102. }
  103.  
  104. void DevBitmap::SetColormapSize(int sz)
  105. {
  106.     if (cmap == 0)
  107.     cmap= new ColorMap(sz);
  108.     else
  109.     cmap->Expand(sz);
  110. }
  111.  
  112. RGB DevBitmap::GetColormapEntry(int ix)
  113. {
  114.     if (cmap == 0)
  115.     cmap= new ColorMap(ix);
  116.     return cmap->GetEntry(ix);
  117. }
  118.  
  119. void DevBitmap::SetColormapEntry(int ix, RGB &rgb)
  120. {
  121.     if (cmap == 0)
  122.     cmap= new ColorMap(ix);
  123.     cmap->SetEntry(ix, rgb);
  124. }
  125.  
  126. void DevBitmap::ReadData(IStream &is, int bpp, int)
  127. {
  128.     int bpl= ((size.x-1)/8+1)*bpp;
  129.     byte *bp= new byte[bpl];
  130.     int y;
  131.     for (y= 0; y < size.y; y++) {
  132.     is.read(bp, bpl);
  133.     SetRow(y, bp, bpl, bpp);
  134.     }
  135.     delete bp;
  136. }
  137.  
  138. void DevBitmap::SetRow(int y, byte *rowdata, int len, int bpp)
  139. {
  140.     register u_long v, m;
  141.     register int x, i= 0, np, j;
  142.     register byte *bp= rowdata;
  143.     
  144.     switch (bpp) {
  145.     case 1:
  146.     for (x= 0; x < len; x++) {
  147.         v= *bp++;
  148.         m= 0x80;
  149.         for (j= 0; j < 8; j++) {
  150.         SetPixel(i++, y, (v & m) ? 1 : 0);
  151.         m >>= 1;
  152.         }
  153.     }
  154.     break;
  155.     case 4:
  156.     for (x= 0; x < len; x++) {
  157.         v= *bp++;
  158.         SetPixel(i++, y, v >> 4);
  159.         SetPixel(i++, y, v & 0xf);
  160.     }
  161.     break;
  162.     case 8:
  163.     case 16:
  164.     case 24:
  165.     case 32:
  166.     np= bpp/8;
  167.     for (x= 0; x < len/np; x++) {
  168.         for (j= 0; j < np; j++)
  169.         v= (v << 8) + *bp++;
  170.         SetPixel(i++, y, v);
  171.     }
  172.     break;
  173.     }
  174. }
  175.  
  176. u_long DevBitmap::GetByte(u_int x, u_int y)
  177. {
  178.     register u_long b= 0;
  179.     register int i;
  180.     
  181.     if (x < 0 || y < 0 || y >= size.y)
  182.     return 0;
  183.     
  184.     switch (depth) {
  185.     case 1:
  186.     x*= 8;
  187.     for (i= 0; i < 8; i++) {
  188.         b <<= 1;
  189.         if (GetPixel(x+i, y))
  190.         b|= 1;
  191.     }
  192.     break;
  193.     case 4:
  194.     x*= 2;
  195.     b= GetPixel(x, y);
  196.     b= (b << 4) + GetPixel(x+1, y);
  197.     break;
  198.     case 8:
  199.     b= GetPixel(x, y);
  200.     break;
  201.     default:
  202.     fprintf(stderr, "DevBitmap::GetByte: depth > 8 not yet implemented\n");
  203.     break;
  204.     }
  205.     return b;
  206. }
  207.  
  208. void DevBitmap::DevBitBlt(int x0, int y0, int w, int h, int op, DevBitmap *s, int sx, int sy)
  209. {
  210.     register int x, y;
  211.     
  212.     for (y= 0; y < h; y++) {
  213.     for (x= 0; x < w; x++) {
  214.         if (op)
  215.         SetPixel(x0+x, y0+y, s->GetPixel(sx+x, sy+y));
  216.         else
  217.         SetPixel(x0+x, y0+y, GetPixel(x0+x, y0+y) | s->GetPixel(sx+x, sy+y));
  218.     }
  219.     }
  220. }
  221.  
  222. DevBitmap *DevBitmap::DevScaleBitmap(Point ss)
  223. {
  224.     int x= size.x, y= size.y, sx= ss.x, sy= ss.y;
  225.     DevBitmap *pr1, *pr2;
  226.     register int b, src, dst, d, a1, a2;
  227.     float scale;
  228.  
  229.     if (sx == x)                // same width
  230.     pr1= this;
  231.     else if (sx < x) {          // x-shrink
  232.     pr1= DevAllocBitmap(Point(sx, y), depth);
  233.     if (depth > 1) {
  234.         scale= (float)x/(float)sx;
  235.         for (dst= 0; dst < sx; dst++)
  236.         if ((b= (int)(dst*scale+0.5)) < x)
  237.             pr1->DevBitBlt(dst, 0, 1, y, TRUE, this, b, 0);
  238.     } else {
  239.         scale= (float)sx/(float)x;
  240.         for (src= 0; src < x; src++)
  241.         if ((b= (int)(src*scale+0.5)) < sx)
  242.             pr1->DevBitBlt(b, 0, 1, y, FALSE, this, src, 0);
  243.     }
  244.     } else {                    // x-magnify
  245.     pr1= DevAllocBitmap(Point(sx, y), depth);
  246.     d= sx/x;
  247.     scale= (float)sx/(float)x;
  248.     for (src= 0; src < x; src++)        // slice
  249.         if ((b= (int)(src*scale+0.5)) < sx)
  250.         pr1->DevBitBlt(b, 0, 1, y, TRUE, this, src, 0);
  251.     for (src= 0; src < d-1; src++)      // smear
  252.         pr1->DevBitBlt(src+1, 0, sx-d+1, y, FALSE, pr1, src, 0);
  253.     for (a1= src= 0; src < x; src++) {  // fill remaining slots
  254.         a2= (int)((src+1)*scale+0.5);
  255.         if (a1+d != a2)
  256.         pr1->DevBitBlt(a2-1, 0, 1, y, TRUE, this, src, 0);
  257.         a1= a2;
  258.     }
  259.     }
  260.     
  261.     if (sy == y)                // same height
  262.     pr2= pr1;
  263.     else if (sy < y) {          // y-shrink
  264.     pr2= DevAllocBitmap(Point(sx, sy), depth);
  265.     if (depth > 1) {
  266.         scale= (float)y/(float)sy;
  267.         for (dst= 0; dst < sy; dst++)
  268.         if ((b= (int)(dst*scale+0.5)) < y)
  269.             pr2->DevBitBlt(0, dst, sx, 1, TRUE, pr1, 0, b);
  270.     } else {
  271.         scale= (float)sy/(float)y;
  272.         for (src= 0; src < y; src++)
  273.         if ((b= (int)(src*scale+0.5)) < sy)
  274.             pr2->DevBitBlt(0, b, sx, 1, FALSE, pr1, 0, src);
  275.     }
  276.     if (pr1 != this)
  277.         delete pr1;
  278.     } else if (sy > y) {        // y-magnify
  279.     pr2= DevAllocBitmap(Point(sx, sy), depth);
  280.     d= sy/y;
  281.     scale= (float)sy/(float)y;
  282.     for (src= 0; src < y; src++)        // slice
  283.         if ((b= (int)(src*scale+0.5)) < sy)
  284.         pr2->DevBitBlt(0, b, sx, 1, TRUE, pr1, 0, src);
  285.     for (src= 0; src < d-1; src++)      // smear
  286.         pr2->DevBitBlt(0, src+1, sx, sy-d+1, FALSE, pr2, 0, src);
  287.     for (a1= src= 0; src < y; src++) {  // fill remaining slots
  288.         a2= (int)((src+1)*scale+0.5);
  289.         if (a1+d != a2)
  290.         pr2->DevBitBlt(0, a2-1, sx, 1, TRUE, pr1, 0, src);
  291.         a1= a2;
  292.     }
  293.     if (pr1 != this)
  294.         delete pr1;
  295.     }
  296.     return pr2;
  297. }
  298.  
  299. void DevBitmap::DevHalftone(WindowColorMap *wcm, DevBitmap *spr)
  300. {
  301.     register int *next, v, error;
  302.     int s= spr->cmap->Size(), *level, *errors, i, x, y, incr, lasterror, *nextbuf;
  303.     u_long *out;
  304.     RGB result;
  305.  
  306.     level= new int[s];
  307.  
  308.     for (i= 0; i < s; i++)
  309.     level[i]= spr->cmap->GetEntry(i).AsGreyLevel();
  310.  
  311.     out= new u_long[256];
  312.     errors= new int[256];
  313.  
  314.     for (i= 0; i < 256; i++) {
  315.     RGB rgb((short)i);
  316.     out[i]= wcm->RGB2Index(&rgb, &result);
  317.     errors[i]= i - result.AsGreyLevel();
  318.     }
  319.  
  320.     nextbuf= new int[size.x + 4];
  321.     next= &nextbuf[2];
  322.  
  323.     for (y= 0; y < size.y; y++) {
  324.     if (y & 1) {   // scan left
  325.         incr= 1;
  326.         i= size.x-1;
  327.     } else {        // scan right
  328.         incr= -1;
  329.         i= 0;
  330.     }
  331.     for (lasterror= x= 0; x < size.x; x++, i-= incr) {
  332.         v= lasterror + level[spr->GetPixel(i, y)];
  333.         if (v < 0)
  334.         v= 0;
  335.         else if (v > 255)
  336.         v= 255;
  337.         SetPixel(i, y, out[v]);
  338.         error= errors[v];
  339.         lasterror= next[i-incr] + (error*7) / 16;
  340.         next[i-incr] = error / 16;
  341.         next[i]     += (error*5) / 16;
  342.         next[i+incr]+= (error*3) / 16;
  343.     }
  344.     }
  345.  
  346.     delete nextbuf;
  347.     delete out;
  348.     delete errors;
  349.     delete level;
  350. }
  351.  
  352. void DevBitmap::DevFloydSteinberg(WindowColorMap *wcm, DevBitmap *spr)
  353. {
  354.     RGB lasterror, error, *nextbuf, *next, rgb, result, v;
  355.     register int s= 256, i, x, y, incr;
  356.  
  357.     nextbuf= new RGB[size.x + 4];
  358.     next= &nextbuf[2];
  359.  
  360.     for (y= 0; y < size.y; y++) {
  361.     if (y & 1) {   // scan left
  362.         incr= 1;
  363.         i= size.x-1;
  364.     } else {        // scan right
  365.         incr= -1;
  366.         i= 0;
  367.     }
  368.     for (x= 0; x < size.x; x++, i-= incr) {
  369.         spr->GetRGB(i, y, &rgb);
  370.         lasterror+= rgb;
  371.         v= lasterror;
  372.         v.Clip();
  373.         SetPixel(i, y, wcm->RGB2Index(&v, &result));
  374.         error= rgb-result;
  375.         lasterror= next[i-incr] + (error*7) / 16;
  376.         next[i-incr] = error / 16;
  377.         next[i]     += (error*5) / 16;
  378.         next[i+incr]+= (error*3) / 16;
  379.     }
  380.     }
  381.  
  382.     delete nextbuf;
  383. }
  384.  
  385. DevBitmap *DevBitmap::FindInCache(WindowColorMap *wcm, Point scale)
  386. {
  387.     register int i;
  388.     register BitmapCache *bmc;
  389.     int wcmid= 0;
  390.     
  391.     if (wcm)
  392.     wcmid= wcm->GetId();
  393.     cacheclock++;
  394.  
  395.     for (i= 0; i < CACHESIZE; i++) {
  396.     bmc= &Cache[(lastix + i) % CACHESIZE];
  397.     if (bmc->org == this && scale == bmc->dbm->Size() && wcmid == bmc->wcmid) {
  398.         bmc->clock= cacheclock;
  399.         return bmc->dbm;
  400.     }
  401.     }
  402.     return 0;
  403. }
  404.  
  405. void DevBitmap::AddToCache(DevBitmap *dbm, WindowColorMap *wcm)
  406. {
  407.     register int i, old= cacheclock;
  408.     register BitmapCache *bmc;
  409.     
  410.     for (lastix= i= 0; i < CACHESIZE; i++) {
  411.     bmc= &Cache[i];
  412.     if (bmc->clock < old) {
  413.         old= bmc->clock;
  414.         lastix= i;
  415.     }
  416.     }
  417.     bmc= &Cache[lastix];
  418.     
  419.     DevBitmap *o1= bmc->org, *o2= bmc->dbm;
  420.     bmc->dbm= bmc->org= 0;
  421.     
  422.     if (o1)
  423.     o1->Unref();
  424.     if (o2)
  425.     o2->Unref();
  426.     
  427.     bmc->dbm= dbm; bmc->dbm->Ref();
  428.     bmc->org= this; bmc->org->Ref();
  429.     
  430.     bmc->wcmid= wcm ? wcm->GetId() : 0;
  431.     bmc->clock= cacheclock;
  432. }
  433.  
  434. bool gDither= TRUE;
  435.  
  436. void DevBitmap::ExpandColors(WindowColorMap *wcm, DevBitmap *dbm, DevBitmap *mask)
  437. {
  438.     ColorMap *cm= dbm->cmap;
  439.     if (cm) {
  440.     if ((cm->IsGrey() || wcm->IsGrey()) && gDither && mask == 0) {
  441.         DevHalftone(wcm, dbm);
  442.     } else {
  443.         register int x, l= cm->Size();
  444.         register u_long *map= new u_long[l];
  445.         
  446.         for (x= 0; x < l; x++)
  447.         map[x]= wcm->RGB2Index(&cm->map[x]);
  448.         if (mask)
  449.         map[0]= 0;
  450.  
  451.         DevMapColors(dbm, map);
  452.  
  453.         delete map;
  454.     }
  455.     } else {    // direct color
  456.     dbm->SetColormapSize(1 << dbm->depth);
  457.     if (gDither && mask == 0) {
  458.         DevFloydSteinberg(wcm, dbm);
  459.     } else {
  460.         RGB rgb;
  461.         register int x, y;
  462.         
  463.         for (x= 0; x < size.x; x++)
  464.         for (y= 0; y < size.y; y++) {
  465.             dbm->GetRGB(x, y, &rgb);
  466.             SetPixel(x, y, wcm->RGB2Index(&rgb));
  467.         }
  468.     }
  469.     }
  470. }
  471.  
  472. void DevBitmap::MapColors(WindowColorMap *wcm, DevBitmap *dbm, DevBitmap *mask)
  473. {
  474.     ExpandColors(wcm, dbm, mask);
  475. }
  476.  
  477. void DevBitmap::ReduceColors(WindowColorMap *wcm, DevBitmap *dbm, DevBitmap *mask)
  478. {
  479.     ExpandColors(wcm, dbm, mask);
  480. }
  481.  
  482. DevBitmap *DevBitmap::PrepareBitmap(WindowPort *port, Point e, DevBitmap *mask)
  483. {
  484.     DevBitmap *dbm, *spm;
  485.     WindowColorMap *wcm= port->ColorMap();
  486.  
  487.     if (dbm= FindInCache(wcm, e))
  488.     return dbm;
  489.  
  490.     dbm= FindInCache(0, e);
  491.     if (dbm == 0) {
  492.     dbm= DevScaleBitmap(e);
  493.     if (cmap && dbm->cmap == 0)
  494.         dbm->cmap= new ColorMap(cmap);
  495.     AddToCache(dbm, 0);
  496.     }
  497.     
  498.     if (cmap == 0 && depth == 1)  // no mapping neccessary
  499.     return dbm;
  500.  
  501.     int portdepth= port->GetDepth();
  502.  
  503.     spm= DevAllocBitmap(e, portdepth);
  504.  
  505.     if (depth < portdepth) {
  506.     spm->ExpandColors(wcm, dbm, mask);
  507.     } else if (depth == portdepth) {
  508.     spm->MapColors(wcm, dbm, mask);
  509.     } else if (depth > portdepth) {
  510.     spm->ReduceColors(wcm, dbm, mask);
  511.     }
  512.     
  513.     AddToCache(spm, wcm);
  514.     return spm;
  515. }
  516.  
  517. //---- abstract methods --------------------------------------------------------
  518.  
  519. DevBitmap *DevBitmap::DevAllocBitmap(Point, u_short)
  520. {
  521.     AbstractMethod("DevBitmap::DevAllocBitmap");
  522.     return 0;
  523. }
  524.  
  525. void DevBitmap::SetPixel(u_int, u_int, u_long)
  526. {
  527.     AbstractMethod("DevBitmap::SetPixel");
  528. }
  529.  
  530. u_long DevBitmap::GetPixel(u_int, u_int)
  531. {
  532.     AbstractMethod("DevBitmap::GetPixel");
  533.     return 0;
  534. }
  535.  
  536. void DevBitmap::SetRGB(u_int, u_int, RGB*)
  537. {
  538.     AbstractMethod("DevBitmap::SetRGB");
  539. }
  540.  
  541. void DevBitmap::GetRGB(u_int, u_int, RGB*)
  542. {
  543.     AbstractMethod("DevBitmap::GetRGB");
  544. }
  545.  
  546.